package org.m8.auth.controller;

import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.collections.MapUtils;
import org.m8.auth.handler.AbstractAuthLoginHandler;
import org.m8.auth.handler.AuthLoginHandlerRegistry;
import org.m8.auth.controller.vo.AuthLoginRespVO;
import org.m8.auth.controller.vo.AuthLogoutReqVO;
import org.m8.auth.controller.vo.AuthRefreshTokenReqVO;
import org.m8.auth.config.SecurityConfig;
import org.m8.auth.security.annotations.PreAuthenticated;
import org.m8.auth.security.util.SecurityFrameworkUtils;
import org.m8.user.model.User;
import org.m8.user.model.UserService;
import org.m8.util.StrUtil;
import org.m8.util.exception.emnus.GlobalErrorCodeConstants;
import org.m8.util.model.CommonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Map;

import static org.m8.util.exception.ServiceExceptionUtil.exception;

/**
 * 用户权限
 *
 * @author yidanjun
 * @date 2024/9/5
 **/
@RestController
@RequestMapping("/auth")
public class AuthLoginController {


    @Resource
    private SecurityConfig securityConfig;

    @Resource
    private UserService userService;
    /**
     *  登录
     *
     * @param reqVO 登录传参
     * @return 登录结果
     */
    @PostMapping("/login")
    @PermitAll // 表示该接口免登录
    public <R extends AuthLoginRespVO> CommonResult<? extends AuthLoginRespVO> login(@RequestBody Map<String, Object> reqVO){
        String loginType = getLoginType(reqVO);
        AbstractAuthLoginHandler authLoginHandler = AuthLoginHandlerRegistry.getInstance().getService(loginType);
        AuthLoginRespVO respVO = authLoginHandler.login(reqVO);
        return CommonResult.success(respVO);
    }

    /**
     * 退出登录
     *
     * @param reqVO 登录凭证
     */
    @PreAuthenticated  // 表示该接口必须登录
    @PostMapping("/logout")
    public CommonResult<Boolean> logout(HttpServletRequest request, @RequestBody AuthLogoutReqVO reqVO) {
        String loginType = reqVO.getLoginType();

        String token = SecurityFrameworkUtils.obtainAuthorization(request,
                securityConfig.getTokenHeader(), securityConfig.getTokenParameter());
        AbstractAuthLoginHandler authLoginHandler = AuthLoginHandlerRegistry.getInstance().getService(loginType);
        authLoginHandler.logout(token);
        return CommonResult.success(true);
    }

    /**
     * 刷新 token
     */
    @PreAuthenticated // 表示该接口必须登录
    @PostMapping("/refreshToken")
    public <V extends AuthLoginRespVO> CommonResult<V> refreshToken(@RequestBody AuthRefreshTokenReqVO reqVO) {
        String loginType = reqVO.getLoginType();
        AbstractAuthLoginHandler authLoginHandler = AuthLoginHandlerRegistry.getInstance().getService(loginType);
        return CommonResult.success(authLoginHandler.refreshToken(reqVO.getRefreshToken()));
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 当前登录用户信息
     */
    @PreAuthenticated // 表示该接口必须登录
    @GetMapping("/getUserInfo")
    public CommonResult<User> getUserInfo(){
        String loginUserId = SecurityFrameworkUtils.getLoginUserId();
        return CommonResult.success(userService.getUser(loginUserId));
    }
    /**
     * 获取登录类型
     *
     * @param reqVO
     * @return
     * @param <T>
     */
    private  String getLoginType(Map<String, Object> reqVO){
        String loginType = MapUtils.getString(reqVO, "loginType");
        if (StrUtil.isEmpty(loginType)){
            throw exception(GlobalErrorCodeConstants.AUTH_LOGIN_TYPE_NOT_EXISTS);
        }
        return loginType;
    }


    @Autowired
    private PasswordEncoder passwordEncoder;

    @PermitAll
    @GetMapping("/testPasswordEncoder")
    public CommonResult<String> testPasswordEncoder(String password){
        return CommonResult.success(passwordEncoder.encode(password));
    }

    @GetMapping("/testAuth")
    public CommonResult<String> testAuth(){
        return CommonResult.success("testAuth");
    }
}
